use std::{rc::Rc, cell::RefCell};

use super::{ClassReader, constant_info::{self, ConstantType, ConstantMethodHandleInfo}};

#[derive(Default)]
pub struct ConstantPool {
    vec: Vec<Option<ConstantType>>
}

impl ConstantPool {
    pub fn read_constant_poll(reader: &mut ClassReader) -> Rc<RefCell<ConstantPool>> {
        let cp_count: usize = reader.read_u16().into();
        let cp = Rc::new(RefCell::new(ConstantPool { vec: Vec::with_capacity(cp_count) }));
        cp.borrow_mut().push(None);
        // 0表示不引用任何常量池项目，索引由1开始
        let mut i = 1;
        while i < cp_count {
            let info = constant_info::read_constant_info(reader, cp.clone());
            if info.long_or_double() {
                // 占用两个位置
                cp.borrow_mut().push(Some(info));
                cp.borrow_mut().push(None);
                i += 2;
            } else {
                cp.borrow_mut().push(Some(info));
                i += 1;
            }
        }
        cp
    }

    // 按索引查找常量
    pub fn get_constant_info(&self, index: usize) -> &ConstantType {
        if let Some(info) = self.vec[index].as_ref() {
            info
        } else {
            panic!("Invalid constant poll index! ")
        }
    }

    // 从常量池查找字段或方法的名称和描述符
    pub fn get_name_and_type(&self, index: usize) -> (String, String) {
        let info = self.get_constant_info(index);
        if let ConstantType::ConstantNameAndType(nt_info) = info {
            let name = self.get_utf8(nt_info.name_index());
            let _type = self.get_utf8(nt_info.descriptor_index());
            (name, _type)
        } else {
            panic!("not found. index{}", index)
        }
        
    }

    // 从常量池查找类名
    pub fn get_class_name(&self, index: usize) -> String {
        let info = self.get_constant_info(index);
        if let ConstantType::ConstantClass(class_info) = info {
            self.get_utf8(class_info.name_index())
        } else {
            panic!("not found. index{}", index)
        }
    }

    // 从常量池查找utf8字符串
    pub fn get_utf8(&self, index: usize) -> String {
        let info = self.get_constant_info(index);
        if let ConstantType::ConstantUtf8(utf8_info) = info {
            utf8_info.str()
        } else {
            panic!("not found. index{}", index)
        }
    }

    pub fn len(&self) -> usize {
        self.vec.len()
    }

    pub fn push(&mut self, item: Option<ConstantType>) {
        self.vec.push(item);
    }

    pub fn get(&self, index: usize) -> &Option<ConstantType> {
        &self.vec[index]
    }

    pub fn get_method_handle(&self, index: usize) -> Option<ConstantMethodHandleInfo> {
        match &self.vec[index] {
            Some(info) => {
                if let ConstantType::ConstantMethodHandle(i) = info {
                    return Some(i.clone());
                }
                panic!("ConstantType is not a ConstantMethodHandle")
            },
            None => None
        }
    }
}
